package moo.stargalaxy_datasyncs.api;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import me.clip.placeholderapi.PlaceholderAPI;
import moo.stargalaxy_bukkit.api.GalaxyAPI;
import moo.stargalaxy_bukkit.config.Config;
import moo.stargalaxy_bukkit.utils.CommandUtil;
import moo.stargalaxy_datasyncs.StarGalaxy_DataSyncs;
import moo.stargalaxy_datasyncs.config.SyncsConfig;
import moo.stargalaxy_datasyncs.data.SyncsData;
import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.GetMethod;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.scheduler.BukkitRunnable;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
import static com.sun.org.apache.xerces.internal.impl.io.UTF8Reader.DEFAULT_BUFFER_SIZE;

public class DataSyncsAPI {

    /**
     * 反序列化String为itemStack
     *
     * @param str 物品str
     * @return ItemStack
     */
    public static ItemStack itemStackDeserialize(String str) {
        YamlConfiguration yml = new YamlConfiguration();
        ItemStack item;
        try {
            yml.loadFromString(str);
            item = yml.getItemStack("item");
        } catch (InvalidConfigurationException ex) {
            item = new ItemStack(Material.AIR, 1);
        }
        return item;
    }

    public static void syncDownAllData(Player player){
        // 设置下方如果用到玩家存档数据时候只需要清空一次背包,避免重复
        boolean CraftINVSataus = false;
        //player.getEnderChest().clear();
        //player.getInventory().clear();


        for (Map.Entry<String, SyncsData> entry : SyncsConfig.getSyncsDataMap().entrySet()) {
            SyncsData syncsData = entry.getValue();
            for (String s : SyncsConfig.getYaml().getStringList("Command_Set.DataSync_Runing")) {
                new BukkitRunnable() {
                    @Override
                    public void run() {
                        CommandUtil.executeCommand(player, s.replaceAll("<datasync_info>", entry.getKey()));
                    }
                }.runTask(StarGalaxy_DataSyncs.getPlugin());
            }
            String data = getData(entry.getKey(), player.getUniqueId().toString(), player.getName());
            if(data.length() == 4){
                Bukkit.getServer().getLogger().info("DataSync - 连接群星控制台出现异常 (已忽略本次处理): " + player.getName());
                continue;
            }
            if(data.startsWith("n200")){
                JSONObject jsonObject = JSON.parseObject(data.substring(4).trim());
                new BukkitRunnable() {
                    @Override
                    public void run() {
                        for (String s : SyncsConfig.getYaml().getStringList("Command_Set.DataSync_Error")) {
                            CommandUtil.executeCommand(player, s.replaceAll("<datasync_info>", entry.getKey()).replaceAll("<datasync_msg>", jsonObject.getString("msg")));
                        }
                    }
                }.runTask(StarGalaxy_DataSyncs.getPlugin());
                continue;
            }
            if(data.contains("空")) continue;
            switch (syncsData.getType()) {
                case "file":
                    String path = StarGalaxy_DataSyncs.getPlugin().getDataFolder().getAbsolutePath();
                    File file = null;
                    if (syncsData.getDatasource().endsWith(".txt")) {
                        file = new File(path.substring(0, path.indexOf("plugins") - 1) + syncsData.getDatasource().replaceAll("<player>", player.getName()).replaceAll("<uuid_formt>", player.getUniqueId().toString()));
                    } else if (syncsData.getDatasource().endsWith(".dat")) {
                        file = new File(path.substring(0, path.indexOf("plugins") - 1) + syncsData.getDatasource().replaceAll("<player>", player.getUniqueId().toString()).replaceAll("<uuid_formt>", player.getUniqueId().toString()));
                    } else {
                        // 其他格式化下直接读写数据内容
                        file = new File(path.substring(0, path.indexOf("plugins") - 1) + syncsData.getDatasource().replaceAll("<player>", player.getUniqueId().toString()).replaceAll("<uuid_formt>", player.getUniqueId().toString()));
                    }

                    if(file == null ){
                        try {
                            file.createNewFile();
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        }
                        //for (String s : SyncsConfig.getYaml().getStringList("Command_Set.DataSync_Error")) {
                        //    CommandUtil.executeCommand(player, s.replaceAll("<datasync_info>", entry.getKey()));
                        //}
                        break;
                    }
                    string2File(data, file.getAbsolutePath());
                    break;
                case "self_data":
                    //使用到原版玩家存档时候先清空一次在做同步数据
                    if(!CraftINVSataus) {
                        // 如果已经清理过了，避免重复清理
                        CraftINVSataus = true;
                        // ----
                        player.getEnderChest().clear();
                        player.getInventory().clear();
                    }

                    if (syncsData.getDatasource().equals("pastatus")) {
                        if (data != null) {
                            YamlConfiguration pastatusYaml = new YamlConfiguration();
                            try {
                                pastatusYaml.loadFromString(data);
                            } catch (InvalidConfigurationException e) {
                                throw new RuntimeException(e);
                            }
                            for (String key : pastatusYaml.getConfigurationSection("").getKeys(false)) {
                                if(key.equals("food")){
                                    player.setFoodLevel(pastatusYaml.getInt(key));
                                    continue;
                                }
                                if(key.equals("exp")){
                                    player.setExp((float) pastatusYaml.getDouble(key));
                                    continue;
                                }
                                if(key.equals("health")){
                                    player.setHealth(pastatusYaml.getDouble(key));
                                    continue;
                                }
                                if(key.equals("buff")){
                                    for (String buff : pastatusYaml.getConfigurationSection("buff").getKeys(false)) {
                                        String string = pastatusYaml.getString("buff." + buff);
                                        String[] split = string.split("-");
                                        player.removePotionEffect(PotionEffectType.getByName(split[0]));
                                        player.addPotionEffect(new PotionEffect(PotionEffectType.getByName(split[0]), Integer.parseInt(split[1]), Integer.parseInt(split[2])),  true);
                                    }
                                }
                            }
                        }
                        break;
                    }
                    if(syncsData.getDatasource().equalsIgnoreCase("gamemode")){
                        YamlConfiguration pastatusYaml = new YamlConfiguration();
                        try {
                            pastatusYaml.loadFromString(data);
                        } catch (InvalidConfigurationException e) {
                            throw new RuntimeException(e);
                        }
                        player.setGameMode(GameMode.valueOf(pastatusYaml.getString("gamemode").toUpperCase()));
                        break;
                    }
                    if (syncsData.getDatasource().equals("inventory")) {
                        YamlConfiguration yaml = new YamlConfiguration();
                        try {
                            yaml.loadFromString(data);
                        } catch (InvalidConfigurationException e) {
                            throw new RuntimeException(e);
                        }
                        addPlayerItem(player, yaml);
                        break;
                    }
                    break;
                case "papi_value":
                    if (syncsData.getDatavaluecmd().length() != 0) {
                        CommandUtil.executeCommand(player, syncsData.getDatavaluecmd().replaceAll("<papi_value>", data));
                        break;
                    }
                    break;
                default:
                    break;
            }
        }
        new BukkitRunnable() {
            @Override
            public void run() {
                for (String s : SyncsConfig.getYaml().getStringList("Command_Set.DataSync_Success")) {
                    CommandUtil.executeCommand(player, s);
                }
            }
        }.runTask(StarGalaxy_DataSyncs.getPlugin());
    }

    // 获取玩家背包全部物品数据
    public static void addPlayerItem(Player player, YamlConfiguration yaml){
        List<ItemStack> inv = new LinkedList<>();
        List<ItemStack> edc = new LinkedList<>();
        for (String key : yaml.getConfigurationSection("").getKeys(false)) {
            String[] s1 = key.split("-");
            ItemStack itemStack = yaml.getItemStack(key);
            if(s1[0].equals("a")){
                if(!itemStack.getType().name().contains("_")) continue;
                String typeItem = itemStack.getType().name().split("_")[1];
                if(typeItem.equals("HELMET")){
                    player.getInventory().setHelmet(itemStack);
                    continue;
                }
                if(typeItem.equals("CHESTPLATE")){
                    player.getInventory().setChestplate(itemStack);
                    continue;
                }
                if(typeItem.equals("LEGGINGS")){
                    player.getInventory().setLeggings(itemStack);
                    continue;
                }
                if(typeItem.equals("BOOTS")){
                    player.getInventory().setBoots(itemStack);
                    continue;
                }
                continue;
            }
            if(s1[0].equals("i")){
                inv.add(itemStack);
                continue;
            }
            if(s1[0].equals("e")){
                edc.add(itemStack);
            }
        }
        ItemStack[] a = new ItemStack[inv.size()];
        ItemStack[] b = new ItemStack[edc.size()];
        int ai = 0, bi = 0;
        for (ItemStack itemStack : inv) {
            a[ai] = itemStack;
            ai++;
        }
        for (ItemStack itemStack : edc) {
            b[bi] = itemStack;
            bi++;
        }
        player.getInventory().setContents(a);
        player.getEnderChest().setContents(b);
    }

    public static void gitAllData(Player player){
        SyncsConfig.getSyncsDataMap().forEach((s, syncsData) -> {
            String data = null;
            try {
                switch (syncsData.getType()){
                    case "file":
                        String path = StarGalaxy_DataSyncs.getPlugin().getDataFolder().getAbsolutePath();
                        File file = null;
                        if(syncsData.getDatasource().endsWith(".txt")){
                            file = new File(path.substring(0, path.indexOf("plugins")-1) + syncsData.getDatasource().replaceAll("<player>", player.getName()).replaceAll("<uuid_formt>", player.getUniqueId().toString()));
                        } else if (syncsData.getDatasource().endsWith(".dat")){
                            file = new File(path.substring(0, path.indexOf("plugins")-1) + syncsData.getDatasource().replaceAll("<player>", player.getUniqueId().toString()).replaceAll("<uuid_formt>", player.getUniqueId().toString()));
                        } else {
                            // 其他格式化下直接读写数据内容
                            file = new File(path.substring(0, path.indexOf("plugins")-1) + syncsData.getDatasource().replaceAll("<player>", player.getUniqueId().toString()).replaceAll("<uuid_formt>", player.getUniqueId().toString()));
                        }
                        if(file == null || !file.exists()) break;
                        data = file2String(file, "UTF-8");
                        break;
                    case "self_data":
                        if(syncsData.getDatasource().equals("pastatus")){
                            YamlConfiguration pastatusYaml = new YamlConfiguration();
                            pastatusYaml.set("exp", player.getExp());
                            pastatusYaml.set("health", player.getHealth());
                            pastatusYaml.set("food", player.getFoodLevel());
                            int size = 0;
                            for (PotionEffect activePotionEffect : player.getActivePotionEffects()) {
                                pastatusYaml.set("buff." + size, activePotionEffect.getType().getName() + "-" + activePotionEffect.getDuration() + "-" + activePotionEffect.getAmplifier());
                                size++;
                            }
                            data = pastatusYaml.saveToString();
                            break;
                        }
                        if(syncsData.getDatasource().equalsIgnoreCase("gamemode")){
                            YamlConfiguration pastatusYaml = new YamlConfiguration();
                            pastatusYaml.set("gamemode", player.getGameMode().name());
                            data = pastatusYaml.saveToString();
                            break;
                        }
                        if(syncsData.getDatasource().equals("inventory")){
                            YamlConfiguration yaml = new YamlConfiguration();
                            int size = 0;
                            for (ItemStack content : player.getInventory().getContents()) {
                                if(content != null && !content.getType().equals(Material.AIR)) {
                                    yaml.set("i-" + size, content);
                                } else {
                                    yaml.set("i-" + size, new ItemStack(Material.AIR));
                                }
                                size++;
                            }
                            size = 0;
                            for (ItemStack armorContent : player.getInventory().getArmorContents()) {
                                if(armorContent != null && !armorContent.getType().equals(Material.AIR)) {
                                    yaml.set("a-" + size, armorContent);
                                } else {
                                    yaml.set("a-" + size, new ItemStack(Material.AIR));
                                }
                                size++;
                            }
                            size = 0;
                            for (ItemStack content : player.getEnderChest().getContents()) {
                                if(content != null && !content.getType().equals(Material.AIR)) {
                                    yaml.set("e-" + size, content);
                                } else {
                                    yaml.set("e-" + size, new ItemStack(Material.AIR));
                                }
                                size++;
                            }
                            data = yaml.saveToString();
                            break;
                        }
                        break;
                    case "papi_value":
                        data = PlaceholderAPI.setPlaceholders(player, syncsData.getDatasource());
                        break;
                    default:
                        break;
                }
                if (data != null) gitPlayerData(s, player.getUniqueId().toString(), player.getName(), data);
            } catch (Exception e){
                Bukkit.getServer().getLogger().info("DataSync - 连接群星控制台出现异常 (已忽略本次处理): " + player.getName());
            }

        });
    }
    public static void gitPlayerData(String dataType, String uuid, String name, String data){
        if(Config.getFid().equals("none") || Config.getFid().equals("")) return;
        String name_encodedUrl = java.net.URLEncoder.encode(name);
        SyncAPI.sendPost(GalaxyAPI.url,"/sub_savegamedata_players?server_fid=" + Config.getFid() + "&data_type=" + dataType.replaceAll("<player>", name).replaceAll("<uuid_formt>", uuid) + "&user_uuid=" + uuid + "&user_name=" + name_encodedUrl, GalaxyAPI.key, data);
    }
    public static String getData(String dataType, String uuid, String name){
        if(Config.getFid().equals("none") || Config.getFid().equals("")) return "no200";
        String name_encodedUrl = java.net.URLEncoder.encode(name);
        return sendGetSync(GalaxyAPI.url,"/sub_getgamedata_players?server_fid=" + Config.getFid() + "&data_type=" + dataType.replaceAll("<player>", name).replaceAll("<uuid_formt>", uuid) + "&user_uuid=" + uuid + "&user_name=" + name_encodedUrl, "utf-8", GalaxyAPI.key);
    }
    public static String sendGetSync(String url, String getType, String charset, String secretkey) {
        HttpClient httpClient = new HttpClient();
        httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(5000);
        GetMethod getMethod = new GetMethod(url + getType);
        getMethod.addRequestHeader("secretkey", secretkey);
        getMethod.addRequestHeader("connection", "Keep-Alive");
        getMethod.addRequestHeader("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
        getMethod.getParams().setParameter("http.socket.timeout", 5000);
        getMethod.getParams().setParameter("http.method.retry-handler", new DefaultHttpMethodRetryHandler());
        String response = "";

        try {
            int statusCode = httpClient.executeMethod(getMethod);
            if (statusCode != 200) {
                return "n200" + response;
            }

            Header[] headers = getMethod.getResponseHeaders();
            byte[] responseBody = getMethod.getResponseBody();
            response = new String(responseBody, charset);
        } catch (HttpException var14) {
            System.out.println("访问控制台连接异常：无法连接到地址或端口 (Unknown Host)");
            var14.printStackTrace();
        } catch (IOException var15) {
            System.out.println("访问控制台连接异常：无法连接到地址或端口 (Connect Error)");
        } finally {
            getMethod.releaseConnection();
        }
        return response;
    }

    /**
     * 文本文件转换为指定编码的字符串
     *
     * @param file         文本文件
     * @param encoding 编码类型
     * @return 转换后的字符串
     * @throws IOException
     */
    public static String file2String(File file, String encoding) {
        InputStreamReader reader = null;
        StringWriter writer = new StringWriter();
        try {
            if (encoding == null || "".equals(encoding.trim())) {
                reader = new InputStreamReader(new FileInputStream(file), encoding);
            } else {
                reader = new InputStreamReader(new FileInputStream(file));
            }
            //将输入流写入输出流
            char[] buffer = new char[DEFAULT_BUFFER_SIZE];
            int n = 0;
            while (-1 != (n = reader.read(buffer))) {
                writer.write(buffer, 0, n);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            if (reader != null)
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
        }
        //返回转换结果
        if (writer != null)
            return writer.toString();
        else return null;
    }

    /**
     * 将字符串写入指定文件(当指定的父路径中文件夹不存在时，会最大限度去创建，以保证保存成功！)
     *
     * @param res      原字符串
     * @param filePath 文件路径
     * @return 成功标记
     */
    public static boolean string2File(String res, String filePath) {
        boolean flag = true;
        BufferedReader bufferedReader = null;
        BufferedWriter bufferedWriter = null;
        try {
            File distFile = new File(filePath);
            if (!distFile.getParentFile().exists()) distFile.getParentFile().mkdirs();
            bufferedReader = new BufferedReader(new StringReader(res));
            bufferedWriter = new BufferedWriter(new FileWriter(distFile));
            String len;
            while ((len = bufferedReader.readLine()) != null) {
                // 这里因为 单引号 ' 有些问题, 做了下面特殊处理
                len = len.replace("&apos;", "'");
                bufferedWriter.write(len);
                bufferedWriter.newLine();
            }
            bufferedWriter.flush();
            bufferedReader.close();
            bufferedWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
            flag = false;
            return flag;
        } finally {
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return flag;
    }

    public static String readFileToHexBinary(String filePath) throws IOException {
        File file = new File(filePath);
        byte[] bytes = new byte[(int) file.length()];
        DataInputStream dis = null;
        try {
            dis = new DataInputStream(new FileInputStream(file));
            dis.readFully(bytes);
        } finally {
            if (dis != null) {
                dis.close();
            }
        }

        StringBuilder hexString = new StringBuilder();
        for (byte b : bytes) {
            hexString.append(String.format("%02x", b));
        }
        return hexString.toString().toLowerCase();
    }



    // 计算玩家UUID算法(v3离线算法) 独立UUID算法
    public static String GetUuidv3Name(String name, boolean Fromt){
        // UUID uuid = UUID.nameUUIDFromBytes((str.getBytes("UTF-8")));
        UUID uuid = UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(StandardCharsets.UTF_8));
        String Textuuid = uuid.toString();
        // 判断是否格式化
        if (!Fromt) {
            return Textuuid.replaceAll("-", "");
        } else {
            return Textuuid;
        }

    }


}
